<template>
  <view :="fv.rootProps" @click="fv.clickReload">
    <view :class="[variables.ns.e('content')]">
      <image :="fv.imageProps"></image>
      <view :class="[variables.ns.e('loading')]">
        <image :src="loadingImage" v-if="lazy" :class="['use-rotate']" mode="heightFix"></image>
      </view>
    </view>
  </view>
</template>

<script lang="ts" setup>
import { ImageNS, variables } from '.'
import { computed, getCurrentInstance, onMounted, reactive, watch } from 'vue'
import { v4 } from 'uuid'
import { onReachBottom } from '@dcloudio/uni-app'

defineOptions({
  name: ImageNS.name
})
const props = defineProps(ImageNS.props)
const emits = defineEmits(ImageNS.emits)
enum LoadStatus {
  loading = 'loading',
  success = 'success',
  error = 'error'
}
const { proxy } = getCurrentInstance()!
const config = {
  observe: <UniApp.IntersectionObserver>{},
}
const state = reactive({
  status: LoadStatus.loading
})
const fv = computed(() => {
  const getObj = () => {
    switch (state.status) {
      case LoadStatus.error:
        return {
          src: props.errorImage,
          clickReload: load,
          class: variables.ns.s('effect')
        }
      case LoadStatus.loading:
        return {
          hitBottomReload: load,
        }
      case LoadStatus.success:
        return {
          src: props.src,
          clickReload: load,
          class: variables.ns.s('effect')
        }
    }
  }
  const obj = getObj()
  const onyId = variables.ns.r(v4())
  const rootProps = {
    class: [
      variables.ns.b,
      variables.ns.s(state.status),
      onyId,
      obj.class
    ],
  }
  const imageProps = {
    ...props.imageProps,
    src: props.lazy ? obj.src : props.src,
    class: [
      variables.ns.e('image'),
    ],
  }
  return {
    rootProps,
    imageProps,
    onyId,
    ...obj
  }
})

function observeImage() {
  const prev = '.' + fv.value.onyId + ' .'
  config.observe?.disconnect?.()
  config.observe = uni.createIntersectionObserver(proxy)
  config.observe.relativeToViewport(props.threshold).observe(
    prev + variables.ns.e('content'),
    obsRes => {
      const { intersectionRatio } = obsRes
      if (intersectionRatio > 0) {
        load()
        config.observe?.disconnect?.()
      }
    }
  )
}

onReachBottom(() => fv.value.hitBottomReload?.())
onMounted(observeImage)
watch(() => props.src, observeImage)

async function load() {
  const startTime = Date.now()
  try {
    state.status = LoadStatus.loading
    emits('loading')

    await uni.getImageInfo({ src: props.src! })

    state.status = LoadStatus.success
    emits('success')
  } catch (error) {
    state.status = LoadStatus.error
    emits('error', error)
  }
  emits('complete', Date.now() - startTime)
}
</script>